
#include <arpa/inet.h>
#include <assert.h>
#include <iostream>
#include <string>
#include "xdns.h"

using namespace std;

const long TEST_SERVER_PORT = 53;
const char TEST_SERVER_IP_ADDRESS[] = "202.99.104.68";
const char TEST_HOSTNAME1[] = "bing.com";
const char TEST_HOSTNAME2[] = "google.com";
const char TEST_ADDRESS1[] = "74.125.128.100";
const char TEST_ADDRESS2[] = "204.79.197.200";

class TestListener : public XdnsListener
{
public:
    TestListener()
    {
    }

    virtual ~TestListener()
    {
    }

    virtual void GetHostCallback(long queryId,
                                 XdnsError error,
                                 const vector<XdnsHostEntry*>* hostEntries)
    {
        if (error != XE_Ok)
        {
            cout<<"An error occured, error code = "<<error<<"."<<endl;
            return;
        }

        assert(hostEntries != NULL);
        assert(!(hostEntries->empty()));
        cout<<"Host entries:"<<endl;

        vector<XdnsHostEntry*>::const_iterator iter = hostEntries->begin();
        vector<XdnsHostEntry*>::const_iterator end = hostEntries->end();
        for (; iter != end; ++iter)
        {
            XdnsHostEntry* hostEntry = *iter;
            assert(hostEntry != NULL);
            string hostname = hostEntry->GetHostname();
            assert(!(hostname.empty()));
            const struct in_addr* address = hostEntry->GetAddress();
            assert(address != NULL);

            cout<<"Hostname: "<<hostname<<", Address: "<<inet_ntoa(*address)<<"."<<endl;
        }
    }
};

int
main()
{
    XdnsError error = XE_Ok;
    XdnsHandler* handler = NULL;
    string errorDescription;

    do
    {
        struct in_addr address1 = {0};
        address1.s_addr = inet_addr(TEST_ADDRESS1);
        if (INADDR_NONE == address1.s_addr)
        {
            cout<<"Test IP address "<<TEST_ADDRESS1<<" is invalid."<<endl;
            break;
        }
        struct in_addr address2 = {0};
        address2.s_addr = inet_addr(TEST_ADDRESS2);
        if (INADDR_NONE == address2.s_addr)
        {
            cout<<"Test IP address "<<TEST_ADDRESS2<<" is invalid."<<endl;
        }

        XdnsConfig config(TEST_SERVER_PORT,
                          TEST_SERVER_IP_ADDRESS);
        error = XdnsHandler::Init(config, &handler, &errorDescription);
        TestListener listener;
        long queryId1 = 0;
        long queryId2 = 0;
        long queryId3 = 0;
        long queryId4 = 0;
        error = (XE_Ok == error) ?
            handler->GetHostByName(TEST_HOSTNAME1, &listener, &queryId1) : error;
        error = (XE_Ok == error) ?
            handler->GetHostByName(TEST_HOSTNAME2, &listener, &queryId2) : error;
        error = (XE_Ok == error) ?
            handler->GetHostByAddress(&address1, &listener, &queryId3) : error;
        error = (XE_Ok == error) ?
            handler->GetHostByAddress(&address2, &listener, &queryId4) : error;
        if (error != XE_Ok)
        {
            break;
        }
        handler->CancelQuery(queryId2);
        handler->CancelQuery(queryId3);

        while (1)
        {
            int nfds = 0;
            fd_set readfds;
            fd_set writefds;
            FD_ZERO(&readfds);
            FD_ZERO(&writefds);
            error = handler->GetProcessingFds(&nfds,
                                              &readfds,
                                              &writefds);
            if (XE_NoEnt == error)
            {
                error = XE_Ok;
                break;
            }
            else if (error != XE_Ok)
            {
                break;
            }

            int selectError = select(nfds,
                                     &readfds,
                                     &writefds,
                                     NULL,
                                     NULL);
            if (selectError < 0)
            {
                cout<<"Function select returns an error!"<<endl;
                break;
            }

            error = handler->Process(&readfds,
                                     &writefds);
            if (error != XE_Ok)
            {
                break;
            }
        }
    }
    while (0);

    if (error != XE_Ok)
    {
        errorDescription = handler->GetLastErrorDescription();
        cout<<errorDescription<<endl;
    }
    XdnsHandler::Release(handler);
    return 0;
}

